import { decode, encode } from "cbor-x"
import { type Product, type Device, type ErrInfo, type Firm, type LoginReq, type QueryRes, type User, createObjectUrl, type Product2 } from "./model"
import router from "@/router"

const DEBUG_BASE_URL = "http://localhost:3001"
const BASE_URL = `${window.location.origin}`

const HTTP_RESP_HEAD = "resp"
const HTTP_RESP_OK = "ok"
const HTTP_RESP_FAIL = "fail"

const REMOTE_TYPE = "type"
const REMOTE_SEQ = "seq"
const REMOTE_CMD = "cmd"
const REMOTE_EC = "ec"

const HTTP_DEVICE_SESSION_HEAD = "device_token"
const HTTP_USER_SERSSION_HEAD = "user_token"

const LOCAL_USER_KEY = "user_info";

let baseURL = DEBUG_BASE_URL;
if (import.meta.env.PROD) {
    baseURL = BASE_URL;
}

let globalUser: User | null = null;

function getUrl(url: string) {
    return `${baseURL}${url}`
}

function getUserInfo() {
    if (globalUser != null) {
        return globalUser;
    }
    let s = localStorage.getItem(LOCAL_USER_KEY);
    if (s != null) {
        globalUser = JSON.parse(s) as User;
        return globalUser;
    }
    router.replace('/login');
    throw `没有用户信息 请登录`
}

function saveUserInfo(user: User) {
    globalUser = user;
    const s = JSON.stringify(user);
    localStorage.setItem(LOCAL_USER_KEY, s);
}

function verifyResp(xhr: XMLHttpRequest) {

    const respHead = xhr.getResponseHeader(HTTP_RESP_HEAD);

    if (xhr.status != 200) {
        throw `http resp ${xhr.statusText}`
    }

    if (respHead == null) {
        throw 'resp head is none'
    }

    const buf = new Uint8Array( xhr.response as ArrayBuffer );

    if (respHead != HTTP_RESP_OK) {
        const info = decode(buf) as ErrInfo;
        if ((info.err_code == 7) || (info.err_code == 8)) {
            router.replace('/login');
        }
        throw `错误码:${info.err_code} ${info.err_msg}`
    }

    return buf;
}

function newHttp(method: 'POST'|'GET', url: string) {
    const xhr = new XMLHttpRequest();
    xhr.timeout = 20 * 1000;
    xhr.responseType = 'arraybuffer';
    xhr.open(method, getUrl(url));
    if (url != '/api/user/login') {
        let id = `${getUserInfo().id}`
        xhr.setRequestHeader(HTTP_USER_SERSSION_HEAD, id);
    }
    return xhr;
}

function createPromise(xhr: XMLHttpRequest) {
    const promise = new Promise((resolve, reject) => {    
        xhr.onerror = () => {
            reject("http 请求错误");
        };
        xhr.ontimeout = () => {
            reject('http 请求超时');
        };
        xhr.onload = resolve;
    });
    return promise;
}

async function get_data(url: string) {
    const xhr = newHttp('GET', url);
    const promise = createPromise(xhr);
    xhr.send();
    await promise;
    const buf = verifyResp(xhr);
    return buf;
}

async function get<T>(url: string) {
    const buf = await get_data(url);
    return decode(buf) as T;
}

async function post<T, R>(url: string, body: T) {
    const xhr = newHttp('POST', url);
    const promise = createPromise(xhr);
    xhr.send(encode(body));
    await promise;
    const buf = verifyResp(xhr);
    return decode(buf) as R;
}

export async function uploadFirm(form: FormData, cb: (p: number) => void) {
    const xhr = newHttp('POST', '/api/firm/upload');
    const promise = createPromise(xhr);
    xhr.upload.addEventListener('progress', (e) => {
        if (e.lengthComputable) {
            const prog = e.loaded / e.total * 100;
            cb(prog);
        }
    });
    xhr.send(form);
    await promise;
    verifyResp(xhr);
}

async function postReturnVoid<T>(url: string, body: T) {
    const xhr = newHttp('POST', url);
    const promise = createPromise(xhr);
    xhr.send(encode(body));
    await promise;
    verifyResp(xhr);
}

export async function query() {
    return get<QueryRes>('/api/device/query')
}

export async function deviceEdit(device: Device) {
    await postReturnVoid('/api/device/edit', device);
}

export async function notify(id: number, cmd: number, body: any) {
    const xhr = newHttp('POST', `/api/remote/notify?id=${id}`);
    xhr.setRequestHeader(REMOTE_CMD, `${cmd}`);
    const promise = createPromise(xhr);
    xhr.send(body)
    await promise;
    verifyResp(xhr);
}

export async function login(req: LoginReq) {
    const user = await post<LoginReq, User>('/api/user/login', req);
    saveUserInfo(user);
    return user;
}

export async function firmQuery(c_type: number) {
    return await get<Firm[]>(`/api/firm/query?c_type=${c_type}`)
}

export async function firmDel(id: number) {
    return await postReturnVoid('/api/firm/del', {
        id
    });
}

export async function productCreate(name: string, price: number, image: Uint8Array) {
    interface CreateReq {
        name: string,
        price: number,
        image: Uint8Array,
    }
    return await post<CreateReq, number>('/api/product/create', {
        name,
        price,
        image
    });
}

export async function productQuery() {
    return await get<Product[]>('/api/product/query');
}

export async function productUpdate(product: Product) {
    await postReturnVoid<Product>('/api/product/edit', product);
}

export async function product2Create(name: string, price: number, image: Uint8Array) {
    interface CreateReq {
        name: string,
        price: number,
        image: Uint8Array,
    }
    return await post<CreateReq, number>('/api/product2/create', {
        name,
        price,
        image
    });
}

export async function product2Edit(id: number, name: string, price: number, image: Uint8Array | null) {
    interface EditReq {
        id: number,
        name: string,
        price: number,
        image: Uint8Array | null
    }
    return await postReturnVoid<EditReq>('/api/product2/edit', {
        id,
        name,
        price,
        image
    });
}

export async function product2ImageUrl(image_id: number) {
    const data = await get_data(`/api/product2/get?image_id=${image_id}`);
    return createObjectUrl(data);
}

export async function product2Query() {
    return await get<Product2[]>('/api/product2/query');
}




